package com.simple.datax.router.impl;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.rpc.RpcException;
import com.simple.datax.SimpleMessage;
import com.simple.datax.api.MessageService;
import com.simple.datax.api.NeedResendSimpleException;
import com.simple.datax.api.Router;
import com.simple.datax.api.RouterException;
import com.simple.datax.api.SimpleException;
import com.simple.datax.core.model.connpara.CommonConnPara;
import com.simple.datax.service.AbstractMessageProcessor;
import com.simple.datax.service.DBLoaderRouteService;
import com.simple.datax.utils.SimpleConstants;

/**
 * @Title: RouterImpl.java
 * @Package com.simple.datax.router.impl
 * @Description: 路由服务的实现
 * @author Paladin Chen
 * @date 2012-12-28 上午10:29:00
 * @version V1.0
 */
public class RouterImpl extends AbstractMessageProcessor implements Router {
	private static final Logger logger = LoggerFactory.getLogger(RouterImpl.class);

	@Autowired
	private DBLoaderRouteService dbRouterService;

	private String localNode = "EC0001";

	// 平台内部的其他服务是否需要和其他的发送方式分开处理
	// 例如：其他的通道使用sender服务，通过ftp，Mq等等方式发到外部；而内部服务通过rpc调用处理
	private boolean intraProcDiff = true;

	private Map<String, MessageService> intraProcessors = new HashMap<String, MessageService>();

	@Override
	public void realProcess(SimpleMessage src) throws SimpleException {
		logger.debug("Begin to Router Service!" + src.toLog());
		this.setErrorInfos(SimpleConstants.ERROR_TYPE_DATAXPROC, SimpleConstants.ERROR_LEVEL_NORMAL,
				SimpleConstants.RESPONSE_CODE_ROUTE, SimpleConstants.RESPONSE_MSG_ROUTE);
		try {
			procRouterInfo((SimpleMessage) src);
		} catch (RpcException e) {
			throw new NeedResendSimpleException("Router:", e);
		} catch (Exception e) {
			logger.debug("Router Error:", e);
			throw new RouterException("Router Error:" + e.getMessage(), e);
		}

		logger.debug("Finish Router Service!" + src.toLog());
	}

	/**
	 * 可能需要分流，区分发向其他交换节点和本地处理，如果和其他的节点
	 * 
	 * @param src
	 * @throws SimpleException
	 */
	private void procRouterInfo(SimpleMessage src) throws SimpleException {
		// 变更FLow报文的接收地址
		procIntraMsgRouterInfo(src);

		String receiver, serviceCode, node;
		CommonConnPara ccp;
		if (localNode.equalsIgnoreCase(src.getReceiverNode())) { // 处理本节点的服务
			receiver = src.getReceiver().toUpperCase();
			serviceCode = src.getServiceCode();

			// 区分发至内部服务
			if (intraProcDiff) {
				if (intraProcessors == null) {
					throw new RouterException("Need config any intra processors.");
				}

				// 对于配置了内部处理的，则使用内部处理器，如果没有，则按企业接受的方式处理
				if (intraProcessors.containsKey(receiver)) {
					MessageService ms = intraProcessors.get(receiver);

					ms.service(src.getContent());

					// 设置通讯方式
					src.setSentCommunType("RPC."+SimpleConstants.FLOW_COMMTYPE_POSTFIX);
					src.setSentCommunParam("Intra RPC");

					// 处理发送完成备份及状态
					this.callBackupService(src);
					this.callStatusService(src);

					return;
				}
			}

			ccp = dbRouterService.getRouterInfo(receiver, serviceCode);
		} else { // 节点间跳转
			node = src.getReceiverNode();
			ccp = dbRouterService.getNodeRouterInfo(node);
		}

		src.setSentCommunParam(ccp.getTransportPara());
		src.setSentCommunType(ccp.getTransportType());
		src.setSentEncoding(ccp.getEncoding());
		src.setSentMsgFormat(ccp.getMsgFormat());
		src.setSentMsgType(ccp.getMsgType());

		this.callNextStep(src);
	}

	/**
	 * 处理从内部服务过来的报文的路由信息
	 * 
	 * @param src
	 */
	private void procIntraMsgRouterInfo(SimpleMessage src) throws SimpleException {
		if (src == null) {
			throw new RouterException("SimpleMessage is null.");
		}
		
		if (src.isIntraMsg()) {
			if (StringUtils.isBlank(src.getReceiverNode())) {
				throw new RouterException("Receiver Node is blank.");
			}
			// 先判断是否为发往TCS的报文，因为报文内容已经由FLow变成tcs数据，则需判断其receiver的编号；并修改SimpleMessage的相应数据
			// 如果需要支持到多个TCS node，receiver后需带@，即数据库中配置时也要带上@
			if (src.getReceiverNode().startsWith("T") || src.getReceiverNode().startsWith("t")) {
				String oriReceiverNode = src.getReceiverNode();
				src.setReceiverNode(localNode);
				src.setReceiver(src.getReceiver() + "@" + oriReceiverNode);
			}
		}
	}

	public String getLocalNode() {
		return localNode;
	}

	public void setLocalNode(String localNode) {
		this.localNode = localNode;
	}

	/**
	 * 
	 * @return
	 */
	public boolean isIntraProcDiff() {
		return intraProcDiff;
	}

	/**
	 * 平台内部服务是否差别处理
	 * 
	 * @param intraProcDiff
	 */
	public void setIntraProcDiff(boolean intraProcDiff) {
		this.intraProcDiff = intraProcDiff;
	}

	public Map<String, MessageService> getIntraProcessors() {
		return intraProcessors;
	}

	public void setIntraProcessors(Map<String, MessageService> intraProcessors) {
		this.intraProcessors = intraProcessors;
	}

}
